﻿//NOTE: https://developer.foursquare.com/docs/explore#req=venues/search%3Fll%3D55.083428,38.805256%26radius%3D300%26intent%3Dbrowse
namespace BlogsAPI.Sites
{
    using System.Threading;
    using FoursquareSharp;
    using Newtonsoft.Json.Linq;
    using System;
    using System.Diagnostics;
    using System.Net;
    using System.Text;
    using System.Text.RegularExpressions;
    using Abstract;

    /// <summary>
    /// Сервис чекинов
    /// </summary>
    [BlogServiceAPI(Description = "Foursquare", Link = "http://foursquare.com")]
    public class Foursquare : BlogServer
    {
        #region Constants

        private static readonly Regex Validation = new Regex(@"^https?://(?:[-_\w]+\.)?(?:foursquare\.com|4sq\.com|swarmapp\.com)", Regexoptions);
        private static readonly Regex ValidationFull = new Regex(@"^https?://(?:[-_\w]+\.)?(?:foursquare\.com|4sq\.com|swarmapp\.com)/([^/]+)(?:/|$)", Regexoptions);
        
        private static readonly Regex CheckinText = new Regex(@"(?<=checkin:)[^{]{.*?}(?=,\s?\w+:)", Regexoptions);
        private static readonly Regex rLocation = new Regex(@"\Wlocation\W:[^{]*({[^}]+})", Regexoptions);

        /// <summary>
        /// Уникальный ключ для простых запросов
        /// </summary>
        public static FoursquareConfig APIKey
            = new FoursquareConfig("https://api.foursquare.com/v2", "https://foursquare.com/oauth2/authenticate",
                "E44ONKYZ0SS5IRXY2YFYMRWAJXTH0WIWILABLLXOLZRC0SSQ", "LULDEHJWMYJJFJ3OQSRKE3O0EJGNPG45N5YDAWT5O0U3D1O0", "");

        #endregion

        #region interface: BlogServer

        [DebuggerStepThrough]
        public Foursquare()
        {
            Encoding = Encoding.UTF8;
        }

        /// <summary>
        /// http://www.t30p.ru/Foursquare.aspx
        /// </summary>
        public override bool HasRating
        {
            get { return true; }
        }

        /// <summary>
        /// проверка, является ли передаваемый урл чатью этого сервиса
        /// </summary>
        public override Boolean ValidateLink(String sLink)
        {
            return Validation.Match(sLink).Success;
        }

        /// <summary>
        /// проверка, является ли передаваемый урл чатью этого сервиса
        /// </summary>
        /// <param name="sLink">ссылка для проверки</param>
        /// <param name="userName">Имя пользователя на блогохостинге</param>
        /// <param name="bType">Тип блога - пользователь или сообщество</param>
        public override Boolean ValidateLink(String sLink, out String userName, out BlogType bType)
        {
            //https://foursquare.com/rederickmind/checkin/4fc7259ee4b0d7c7650bc2e6?s=tgULjJyRXG_lycIjpS81h90RIao&ref=tw
            //https://www.swarmapp.com/vyazemskiy/checkin/5176cfbae4b05eab831375ec?s=EqI8ESObxl0aZw6GPHQILB00ghs&ref=tw
            bType = BlogType.Unknown;
            Match m = ValidationFull.Match(sLink);
            if (m.Success)
            {
                bType = BlogType.User;
                userName = m.Groups[1].ToString();
            }
            else
            {
                userName = String.Empty;
            }
            return m.Success;
        }

        /// <summary>
        /// Получение ссылки на блог блогера
        /// </summary>
        /// <param name="userName">ник блогера</param>
        /// <param name="btype">Тип блога - пользователь или сообщество</param>
        public override String GetBlogLink(string userName, BlogType btype)
        {
            return String.Format("http://foursquare.com/{0}", userName);
        }

        #endregion

        #region IPost

        /// <summary>
        /// Получение одного поста по ссылке на него и данных о пользователе
        /// </summary>
        /// <param name="linkOnPost">ссылка на пост</param>
        public override BlogPost GetOnePost(string linkOnPost)
        {
            return GetOnePost(linkOnPost, "", BlogType.Unknown);
        }

        /// <summary>
        /// Получение одного поста по ссылке на него и данных о пользователе
        /// </summary>
        /// <param name="linkOnPost">ссылка на пост</param>
        /// <param name="userName">имя пользователя</param>
        /// <param name="btype">тип блогплатформы</param>
        /// <remarks>Может генерить исключения</remarks>
        public override BlogPost GetOnePost(string linkOnPost, string userName, BlogType btype)
        {
            CheckIn check;
            return GetOnePost(linkOnPost, out check);
        }

        /// <summary>
        /// Получение одного поста по ссылке на него и данных о пользователе
        /// </summary>
        /// <param name="linkOnPost">ссылка на пост</param>
        /// <param name="cin">данные места</param>
        /// <remarks>Может генерить исключения</remarks>
        public BlogPost GetOnePost(string linkOnPost, out CheckIn cin)
        {
            cin = null;
            if (!ValidateLink(linkOnPost))
            {
                return null;
            }
            BlogPost bp = BlogPost.SimpleLink(linkOnPost);
            try
            {
                string result = String.Empty;
                try
                {
                    result = PerformRequest(linkOnPost, true);
                }
                catch (WebException we)
                {
                    if (((HttpWebResponse) we.Response).StatusCode == HttpStatusCode.InternalServerError)
                    {
                        Thread.Sleep(10000);//ждем в случае, если сервер удаленный не работает
                    }
                    linkOnPost = linkOnPost.Replace("://", "://www.");//добавляем www для обращения через CNAME а не @, глючит часто
                    result = PerformRequest(linkOnPost, true);
                }
                //получаем ответ и его разбираем...
                Match mc = CheckinText.Match(result);
                if (mc.Success)
                {
                    cin = Mapper.Map<CheckIn>(mc.Groups[0].Value.Replace("\\/", "/")) as CheckIn;
                    if (cin != null)
                    {
                        bp.Subject = String.Format("{0} {1}:{2}{3}{4}", cin.User.FirstName, cin.User.LastName, cin.Shout,
                            cin.Venue==null?"":" "+cin.Venue.Name,
                            cin.Location == null || String.IsNullOrEmpty(cin.Location.Address) ? "" : " @ " + cin.Location.Address
                            );
                        bp.Published = cin.CreatedAt;
                        string[] datas = cin.User.CanonicalUrl.Split('/');
                        bp.SpecialParam = datas[datas.Length-1];//blogname
                        bp.Existance = true;
                        //если есть фотография
                        if (cin.Location != null)
                        {
                            bp.Attributes.Add(new PostAttribute(PostParams.Tags, (cin.Location.City+","+cin.Location.Country).Trim(',')));
                        }
                        if (cin.Venue != null)
                        {
                            bp.Views = cin.Venue.Stats.CheckinsCount;
                        }
                        if (cin.Comments != null)
                        {
                            bp.Comments = cin.Comments.Count;
                        }
                        if (cin.Photos != null && cin.Photos.Items!=null && cin.Photos.Items.Count > 0)
                        {
                            var img = cin.Photos.Items[0].GetPhoto();
                            if (!String.IsNullOrEmpty(img))
                            {
                                bp.Attributes.Add(new PostAttribute(PostParams.MediaThumbnail,img));
                            }
                        }
                        if (cin.Location != null)
                        {
                            bp.Attributes.Add(new PostAttribute(PostParams.Location,
                                                                String.Format("{0} {1}", cin.Location.Lat,
                                                                              cin.Location.Lng)));
                        }
                    }
                }
            }
            catch (Exception e1)
            {
                Trace.Write(linkOnPost+": "+e1.Message);
            }
            return bp;
        }

        #endregion

        /// <summary>
        /// Получение описания места по ссылке типа http://4sq.com
        /// </summary>
        /// <param name="sLink"></param>
        /// <returns></returns>
        public JObject GetLocation(string sLink)
        {
            if (!ValidateLink(sLink))
            {
                return null;
            }
            try
            {
                string result = PerformRequest(sLink,true);
                //ПОЛУЧИЛИ xml - откроемка его...
                Match mc = rLocation.Match(result);
                if (mc.Success)
                {
                    return JObject.Parse(mc.Groups[1].Value);
                }
            }catch(Exception e1)
            {
                Debug.WriteLine(e1.Message);
            }
            return null;
        }
    }
}